package script.node;

import cn.hutool.core.date.StopWatch;
import cn.hutool.core.util.HexUtil;
import com.gee.spring.cloud.aerospace.simulate.core.domain.TelemetryNodeDto;
import com.gee.spring.cloud.aerospace.simulate.core.satellite.telemetry.TmFrameGenerator;
import com.gee.spring.cloud.aerospace.simulate.core.util.ByteUtil;

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author gepengjun
 * @since 2024/7/4 17:24
 */
public class ByChildren {

    static byte[] eval(TmFrameGenerator tmFrameGenerator, TelemetryNodeDto currentNode,
                       List<TelemetryNodeDto> frameNodeList, Map<String, String> scriptParamMap){
        List<TelemetryNodeDto> childrenDtoList = currentNode.getChildrenDto();
        List<TelemetryNodeDto> orderedChildrenDtoList = childrenDtoList.stream()
                .sorted(Comparator.comparingInt(TelemetryNodeDto::getSiblingAssembleOrder))
                .collect(Collectors.toList());
        byte[] currentNodeBytes = null;
        for (TelemetryNodeDto child : orderedChildrenDtoList){
            byte[] childBytes = child.getBytes();
            byte[] shiftLeft = ByteUtil.shiftLeft(childBytes, child.getBitEnd());
            //调整为字节占字节数，字节数向上取整
            int byteLength = child.getByteEnd() - child.getByteBegin() + 1;
            byte[] childNewBytes = ByteUtil.interceptOrFillLeft(shiftLeft, byteLength);
            currentNodeBytes = ByteUtil.mergeWithBit(currentNodeBytes, childNewBytes);
        }
        return currentNodeBytes;
    }

    public static void main(String[] args) {
        //TelemetryNodeDto telemetryNodeDto = assembleSignalNode();
        //TelemetryNodeDto telemetryNodeDto = assembleMarkNode();
        //TelemetryNodeDto telemetryNodeDto = assembleVerAndMarkNode();
        TelemetryNodeDto telemetryNodeDto = assembleMpduHeadNode();
        StopWatch stopWatch = StopWatch.create("byChildren");
        stopWatch.start();
        byte[] eval = eval(null, telemetryNodeDto, null, null);
        stopWatch.stop();
        System.out.println(stopWatch.prettyPrint(TimeUnit.MILLISECONDS));
        String hexStr = HexUtil.encodeHexStr(eval);
        System.out.println(hexStr);
        System.out.println(Long.toBinaryString(HexUtil.hexToLong(hexStr)));
    }

    private static TelemetryNodeDto assembleSignalNode(){
        TelemetryNodeDto signalNode = new TelemetryNodeDto();
        signalNode.setNodeName("信号域"); //80

        TelemetryNodeDto playBackNode = new TelemetryNodeDto();
        playBackNode.setNodeName("回放标志");
        playBackNode.setBytes(HexUtil.decodeHex("01"));
        playBackNode.setBitEnd(7);
        playBackNode.setByteBegin(0);
        playBackNode.setByteEnd(0);
        playBackNode.setBitEnd(7);
        playBackNode.setSiblingAssembleOrder(1);


        TelemetryNodeDto backupNode = new TelemetryNodeDto();
        backupNode.setNodeName("备用");
        backupNode.setBytes(HexUtil.decodeHex("00"));
        backupNode.setBitEnd(0);
        backupNode.setByteBegin(0);
        backupNode.setByteEnd(0);
        backupNode.setSiblingAssembleOrder(2);

        List<TelemetryNodeDto> children = List.of(playBackNode, backupNode);
        signalNode.setChildrenDto(children);
        return signalNode;
    }

    private static TelemetryNodeDto assembleMarkNode(){
        TelemetryNodeDto markNode = new TelemetryNodeDto();
        markNode.setNodeName("标识符"); //0841

        TelemetryNodeDto spaceNode = new TelemetryNodeDto();
        spaceNode.setNodeName("航天器标识符");
        spaceNode.setBytes(HexUtil.decodeHex("21"));
        spaceNode.setBitBegin(5);
        spaceNode.setBitEnd(6);
        spaceNode.setByteBegin(0);
        spaceNode.setByteEnd(1);
        spaceNode.setSiblingAssembleOrder(1);


        TelemetryNodeDto vcNode = new TelemetryNodeDto();
        vcNode.setNodeName("虚拟信道标志");
        vcNode.setBytes(HexUtil.decodeHex("01"));
        vcNode.setBitBegin(5);
        vcNode.setBitEnd(0);
        vcNode.setByteBegin(1);
        vcNode.setByteEnd(1);
        vcNode.setSiblingAssembleOrder(2);

        List<TelemetryNodeDto> children = List.of(spaceNode, vcNode);
        markNode.setChildrenDto(children);
        return markNode;
    }

    private static TelemetryNodeDto assembleVerAndMarkNode(){
        TelemetryNodeDto versionMarkNode = new TelemetryNodeDto();
        versionMarkNode.setNodeName("版本和标识符"); //100100001000001

        TelemetryNodeDto versionNode = new TelemetryNodeDto();
        versionNode.setNodeName("版本号");
        versionNode.setBytes(HexUtil.decodeHex("01"));
        versionNode.setBitBegin(7);
        versionNode.setBitEnd(6);
        versionNode.setByteBegin(0);
        versionNode.setByteEnd(0);
        versionNode.setSiblingAssembleOrder(1);


        TelemetryNodeDto markNode = new TelemetryNodeDto();
        markNode.setNodeName("标识符");
        markNode.setBytes(HexUtil.decodeHex("0841"));
        markNode.setBitBegin(5);
        markNode.setBitEnd(0);
        markNode.setByteBegin(0);
        markNode.setByteEnd(1);
        markNode.setSiblingAssembleOrder(2);

        List<TelemetryNodeDto> children = List.of(versionNode, markNode);
        versionMarkNode.setChildrenDto(children);
        return versionMarkNode;
    }


    private static TelemetryNodeDto assembleMpduHeadNode(){
        TelemetryNodeDto mpduHeadNode = new TelemetryNodeDto();
        mpduHeadNode.setNodeName("M-PDU导头"); //100100001000001

        TelemetryNodeDto standbyNode = new TelemetryNodeDto();
        standbyNode.setNodeName("备用");
        standbyNode.setBytes(HexUtil.decodeHex("0"));
        standbyNode.setBitBegin(7);
        standbyNode.setBitEnd(3);
        standbyNode.setByteBegin(0);
        standbyNode.setByteEnd(0);
        standbyNode.setSiblingAssembleOrder(1);


        TelemetryNodeDto firstHeadPointNode = new TelemetryNodeDto();
        firstHeadPointNode.setNodeName("首导头指针");
        firstHeadPointNode.setBytes(HexUtil.decodeHex("11F"));
        firstHeadPointNode.setBitBegin(2);
        firstHeadPointNode.setBitEnd(0);
        firstHeadPointNode.setByteBegin(0);
        firstHeadPointNode.setByteEnd(1);
        firstHeadPointNode.setSiblingAssembleOrder(2);

        List<TelemetryNodeDto> children = List.of(standbyNode, firstHeadPointNode);
        mpduHeadNode.setChildrenDto(children);
        return mpduHeadNode;
    }
}
